package club.kynb.mall.product.service.impl;

import club.kynb.mall.product.api.IProductCategoryService;
import club.kynb.mall.product.convert.ProductConvertor;
import club.kynb.mall.product.dto.ProductCategoryDTO;
import club.kynb.mall.product.dto.ProductCategoryFullDTO;
import club.kynb.mall.product.dto.ProductCategoryParamDTO;
import club.kynb.mall.product.mysql.mapper.ProductCategoryMapper;
import club.kynb.mall.product.mysql.mapper.ProductSpuMapper;
import club.kynb.mall.product.mysql.po.ProductCategoryPO;
import club.kynb.mall.product.mysql.po.ProductSpuPO;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.pizza.common.web.exception.Errors;
import org.pizza.model.page.PageResult;
import org.pizza.mybatis.plus.support.Pages;
import org.pizza.util.Checker;
import org.pizza.util.Convertor;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author kynb_club@163.com
 * @date: 2021/6/24
 */
@Service
@AllArgsConstructor
public class ProductCategoryServiceImpl implements IProductCategoryService {

    final ProductCategoryMapper productCategoryMapper;
    final ProductSpuMapper productSpuMapper;

    @Override
    public List<ProductCategoryDTO> listByParent(long parentId) {
        List<ProductCategoryPO> productCategoryPOS = productCategoryMapper.selectList(
                Wrappers.<ProductCategoryPO>lambdaQuery().eq(ProductCategoryPO::getParentId, parentId)
                        .orderByAsc(ProductCategoryPO::getSequence)
        );
        return ProductConvertor.convert(productCategoryPOS, ProductCategoryDTO.class);
    }

    @Override
    public List<ProductCategoryDTO> listByIds(List<Long> categoryIds) {
        if(CollectionUtil.isEmpty(categoryIds)){
            return new ArrayList<>();
        }
        List<ProductCategoryPO> productCategoryPOS = productCategoryMapper.selectList(
                Wrappers.<ProductCategoryPO>lambdaQuery().in(ProductCategoryPO::getId, categoryIds)
                        .orderByAsc(ProductCategoryPO::getSequence)
        );
        return ProductConvertor.convert(productCategoryPOS, ProductCategoryDTO.class);
    }

    @Override
    public PageResult<ProductCategoryDTO> pageProductCategory(ProductCategoryParamDTO dto) {
        final LambdaQueryWrapper<ProductCategoryPO> queryWrapper = Wrappers.<ProductCategoryPO>lambdaQuery()
                .eq(ProductCategoryPO::getParentId, dto.getParentId());
        String cateName = dto.getCateName();
        if (StringUtils.isNotBlank(cateName)) {
            queryWrapper.like(ProductCategoryPO::getCateName, cateName);
        }
        queryWrapper.orderByAsc(ProductCategoryPO::getSequence);
        IPage<ProductCategoryPO> pageParam = Pages.convert(dto);
        IPage<ProductCategoryPO> page = productCategoryMapper.selectPage(pageParam, queryWrapper);
        return Pages.convert(page, ProductCategoryDTO.class);
    }


    @Override
    public List<ProductCategoryFullDTO> listFull() {
        List<ProductCategoryPO> productCategoryPOS = productCategoryMapper.selectList(null);
        if(CollectionUtil.isEmpty(productCategoryPOS)){
            return new ArrayList<>();
        }
        Map<Long, List<ProductCategoryPO>> categoryMaps = productCategoryPOS.stream().collect(Collectors.groupingBy(ProductCategoryPO::getParentId));
        return categoryMaps.get(NumberUtils.LONG_ZERO)
                .stream()
                .sorted(Comparator.comparing(ProductCategoryPO::getSequence))
                .map(po -> {
                    ProductCategoryFullDTO fullDTO = ProductConvertor.convert(ProductCategoryFullDTO.class, po);
                    List<ProductCategoryPO> categoryPOS = categoryMaps.get(po.getId());
                    if(CollectionUtil.isEmpty(categoryPOS)){
                        return fullDTO;
                    }
                    fullDTO.setSubList(ProductConvertor.convert(categoryMaps.get(po.getId()).stream().sorted(Comparator.comparing(ProductCategoryPO::getSequence)).collect(Collectors.toList()), ProductCategoryDTO.class));
                    return fullDTO;
                }).collect(Collectors.toList());
    }


    @Override
    public void createProductCategory(ProductCategoryDTO dto) {
        final ProductCategoryPO productCategoryPO = Convertor.convert(ProductCategoryPO.class, dto);
        final int insert = productCategoryMapper.insert(productCategoryPO);
        Checker.ifNotThrow(insert > 0, () -> Errors.SYSTEM.exception("系统异常，添加商品分类失败！"));
    }

    @Override
    public void updateProductCategory(ProductCategoryDTO dto) {
        final ProductCategoryPO productCategoryPO = Convertor.convert(ProductCategoryPO.class, dto);
        final int update = productCategoryMapper.updateById(productCategoryPO);
        Checker.ifNotThrow(update > 0, () -> Errors.SYSTEM.exception("系统异常，修改商品分类失败！"));
    }

    @Override
    public void deleteProductCategory(Long id) {
        final Integer count = productCategoryMapper.selectCount(Wrappers.<ProductCategoryPO>lambdaQuery().eq(ProductCategoryPO::getParentId, id));
        Checker.ifThrow(count > 0, () -> Errors.BIZ.exception("已绑定二级分类，无法删除"));

        Checker.ifThrow(existbyCateId(id), () -> Errors.SYSTEM.exception("已绑定商品，无法删除"));

        final int delete = productCategoryMapper.deleteById(id);
        Checker.ifNotThrow(delete > 0, () -> Errors.SYSTEM.exception("系统异常，删除商品分类失败"));
    }

    @Override
    public Optional<ProductCategoryDTO> detailById(Long id) {
        ProductCategoryPO productCategoryPO = productCategoryMapper.selectById(id);
        if (Objects.isNull(productCategoryPO)) {
            return Optional.empty();
        }
        return Optional.of(ProductConvertor.convert(ProductCategoryDTO.class, productCategoryPO));
    }

    @Override
    public Optional<ProductCategoryDTO> getByName(Long parentId, String cateName) {
        Optional<ProductCategoryPO> first = productCategoryMapper.selectList(Wrappers.<ProductCategoryPO>lambdaQuery().eq(ProductCategoryPO::getParentId, parentId).eq(ProductCategoryPO::getCateName, cateName)).stream().findFirst();
        return first.map(po->ProductConvertor.convert(ProductCategoryDTO.class, po));
    }

    @Override
    public boolean existCategory(Long parentId, String cateName) {
        return getByName(parentId,cateName).isPresent();
    }


    /**
     * 商品是否存在此分类
     * @param cateId
     * @return
     */
    public boolean existbyCateId(Long cateId) {
        LambdaQueryWrapper<ProductSpuPO> wrapper = Wrappers.<ProductSpuPO>lambdaQuery()
                .apply("FIND_IN_SET ({0}, category_ids )", cateId)
                .last("Limit 1");
        ProductSpuPO productSpuP0 = productSpuMapper.selectOne(wrapper);
        return productSpuP0 != null;
    }




}
